﻿<template id="single_table_template">
    <div class="page-table-box" v-loading="loading" element-loading-background="rgba(255, 255, 255, 0.5)" ref="boxRef">
        <div v-if="!customSearch" v-show="searchColumns&&searchColumns.length&&searchShow" class="page-table-search" :style="searchStyle()">
            <div v-for="(item, index) in searchColumns" :key="index" :index="index" class="page-table-search-item" :style="searchItemStyle(index)">
                <div class="search-item-label">
                    <span>{{item.title}}</span>
                    <span>:</span>
                </div>
                <div class="search-item-content">
                    <el-select v-if="item.type=='select'" v-model="searchParams[item.prop]" :clearable="!item.noClearable" :placeholder="item.placeholder" v-on:change="searchAuto(item.auto)">
                        <el-option v-for="(eitem,eindex) in item.enums" :key="eindex" :value="eitem.value" :label="eitem.label"></el-option>
                    </el-select>
                    <el-tree-select v-else-if="item.type=='select_tree'" v-model="searchParams[item.prop]" filterable :clearable="!item.noClearable" node-key="Id" check-strictly :placeholder="item.placeholder" v-on:change="searchAuto(item.auto)" :data="item.data" :props="item.props"></el-tree-select>
                    <el-date-picker v-else-if="item.type=='year'" v-model="searchParams[item.prop]" type="year" value-format="YYYY" :clearable="!item.noClearable" :placeholder="item.placeholder" v-on:change="searchAuto(item.auto)"></el-date-picker>
                    <el-date-picker v-else-if="item.type=='month'" v-model="searchParams[item.prop]" type="month" value-format="YYYY-MM" :clearable="!item.noClearable" :placeholder="item.placeholder" v-on:change="searchAuto(item.auto)"></el-date-picker>
                    <el-date-picker v-else-if="item.type=='date'" v-model="searchParams[item.prop]" type="date" value-format="YYYY-MM-DD" :clearable="!item.noClearable" :placeholder="item.placeholder" v-on:change="searchAuto(item.auto)"></el-date-picker>
                    <el-input v-else v-model="searchParams[item.prop]" :type="item.type" :clearable="!item.noClearable" :placeholder="item.placeholder" v-on:keyup.enter.native="search"></el-input>
                </div>
            </div>
            <div class="page-table-search-right" :style="searchToolsStyle()">
                <el-button type="primary" icon="Search" v-on:click="search">搜索</el-button>
                <el-button icon="Delete" v-on:click="searchReset">重置</el-button>
                <el-button v-if="searchColumns&&searchColumns.length>=gridCols" type="primary" link class="search-isOpen" v-on:click="collapsed=!collapsed">
                    <span>{{collapsed?"展开":"合并"}}</span>
                    <el-icon class="el-icon--right">
                        <component :is="collapsed?'ArrowDown':'ArrowUp'"></component>
                    </el-icon>
                </el-button>
            </div>
        </div>
        <div v-else v-show="searchShow" class="page-table-search" :style="searchStyle()">
            <slot name="custom-search" :search-columns="searchColumns"></slot>
        </div>
        <div class="page-table-main">
            <div v-if="!hideHeader" class="page-table-header">
                <div class="page-table-header-left">
                    <slot name="header-left" :selected-list="selectedList" :selected-list-ids="selectedListIds" :is-selected="isSelected" :query-params="queryParams"></slot>
                </div>
                <div class="page-table-header-right">
                    <slot name="header-right" :data-list="processTableData"></slot>
                    <el-button v-if="!hideHeaderRight&&!hideHeaderRefresh" icon="Refresh" circle v-on:click="loadData"></el-button>
                    <el-button v-if="!hideHeaderRight&&!hideColumnFilter" icon="Operation" circle v-on:click="columnFilter=true;"></el-button>
                    <el-button v-if="!hideHeaderRight&&((searchColumns&&searchColumns.length)||customSearch)" icon="Search" circle v-on:click="searchShow=!searchShow;"></el-button>
                </div>
            </div>
            <el-table class="page-table" :data="processTableData" :border="border" :row-key="rowKey" :height="height" v-on:selection-change="selectionChange" v-bind="$attrs" :summary-method="getSummaries" ref="tableRef" :style="styles">
                <el-table-column v-if="sortableHandle" width="50" align="center">
                    <template #header>
                        <el-icon><Rank /></el-icon>
                    </template>
                    <template #default>
                        <div class="single_table_sortable_drag" style="cursor:move;">
                            <el-icon><Rank /></el-icon>
                        </div>
                    </template>
                </el-table-column>
                <single_table_filter ref="columnFilterRef"></single_table_filter>
                <template #empty>
                    <div class="page-table-empty">
                        <slot name="empty">
                            <img src="/work/images/not_data.png" />
                            <div>暂无数据</div>
                        </slot>
                    </div>
                </template>
            </el-table>
            <!-- 分页组件 -->
            <el-pagination v-if="pagination" :background="true" :current-page="queryParams.pageNum" :page-size="queryParams.pageSize" :page-sizes="[10, 25, 50, 100]" :total="queryParams.total"
                           :layout="layout" v-on:size-change="handleSizeChange" v-on:current-change="handleCurrentChange"></el-pagination>
        </div>
        <el-drawer v-model="columnFilter" title="显示 / 隐藏 列" direction="rtl" size="320px">
            <el-descriptions :column="1" border>
                <template v-for="(col, index) in $refs.columnFilterRef.columnOpts" :key="col">
                    <el-descriptions-item v-if="col.filterable" :label="col.label" label-align="center" align="center">
                        <el-switch v-model="col.visible"></el-switch>
                    </el-descriptions-item>
                </template>
            </el-descriptions>
        </el-drawer>
    </div>
</template>
<script type="text/javascript">
    var single_table = {
        template: "#single_table_template",
        data() {
            return {
                collapsed: true,
                baseTableData: [],
                summaryData: null,
                processTableData: [],
                loading: false,
                searchShow: true,
                queryParams: {},
                searchParams: {},
                customParams: {},
                selectedList: [],
                selectedListIds: [],
                isSelected: false,
                gridCols: 5,
                columnFilter: false,
                columnOpts: [],
                styles: {},
                sortableOrders: [],
                sortableHandle: false,
                sortableInstance: null,
                layout: "total, sizes, prev, pager, next, jumper"
            }
        },
        props: ["api", "loadSuccess", "setDataSuccess", "border", "isTree", "rowKey", "searchColumns", "pagination", "baseQuery", "hideHeader", "hideHeaderRefresh", "hideHeaderRight", "hideColumnFilter", "noAutoLoad", "height", "notMobile", "paginationLayout", "customSearch", "onSortableRow"],
        watch: {
            notMobile(oldVal, newVal) {
                this.columnFilterInit();
            }
        },
        methods: {
            init() {
                var that = this;
                new ResizeObserver((entries) => {
                    for (let entry of entries) {
                        that.resize(entry.contentRect.width);
                    }
                }).observe(that.$refs.boxRef);
                that.columnFilterInit();
                that.searchInit();
                that.heightInit();
                that.layoutInit();
                that.sortableInit();
                if (!this.noAutoLoad) { this.loadData(); }
            },
            destroy() {
                if (this.sortableHandle && this.sortableInstance) {
                    this.sortableInstance.destroy();
                }
                window.removeEventListener("resize", this.resize);
            },
            sortableInit() {
                var that = this;
                that.sortableHandle = that.onSortableRow != null;
                if (that.sortableHandle) {
                    var table = that.$refs.tableRef;
                    var tbody = table.$el.querySelector(".el-table__body-wrapper tbody");
                    that.sortableInstance = Sortable.create(tbody, {
                        handle: ".single_table_sortable_drag",
                        animation: 150,
                        onEnd({ oldIndex, newIndex }) {
                            // 将oldIndex位置的数据删除并取出，oldIndex后面位置的数据会依次前移一位
                            const currentRow = that.processTableData.splice(oldIndex, 1)[0]; 
                            // 将被删除元素插入到新位置（currRow表示上面的被删除数据）
                            that.processTableData.splice(newIndex, 0, currentRow);
                            // 提取数据变更的内容
                            var start = oldIndex < newIndex ? oldIndex : newIndex;
                            var end = oldIndex > newIndex ? oldIndex : newIndex;
                            var rows = that.processTableData.slice(start, end + 1);
                            that.onSortableRow(oldIndex, newIndex, rows);
                        }
                    });
                }
            },
            heightInit() {
                if (this.height) {
                    this.styles['flex'] = 'none';
                }
            },
            layoutInit() {
                if (this.paginationLayout) { this.layout = this.paginationLayout; }
            },
            resize(width) {
                var that = this;
                var count = ((width / 250) >> 0) - 1;
                if (count < 1) { count = 1; }
                if (that.gridCols != count) { that.gridCols = count; }
            },
            columnFilterInit() {
                var slots = this.$slots.default();
                this.columnOpts = this.$refs.columnFilterRef.init(slots);
            },
            loadData(params) {
                var that = this;
                if (that.api) {
                    $.ajax({
                        url: that.api,
                        type: "get",
                        data: that.queryParams,
                        dataType: "json",
                        beforeSend() {
                            that.loading = true;
                        },
                        complete() {
                            that.loading = false;
                        },
                        success(result) {
                            if (that.loadSuccess) {
                                result = that.loadSuccess(result);
                            }
                            that.setData(result.data);
                        },
                        error(request, status, error) {
                            if (request.status != 400) {
                                app.func.error("系统错误，请查看错误日志");
                                console.info(request);
                            }
                            else { app.func.ajaxLogout(request.responseText); }
                        }
                    });
                }
            },
            setData(data) {
                var that = this;
                that.baseTableData = data.rows;
                that.summaryData = data.summary;
                that.queryParams.total = data.total || data.rows.length;
                that.processTableData = that.structureTree(that.baseTableData, 0);
                if (that.setDataSuccess) { that.setDataSuccess(); }
            },
            structureTree(data, pid) {
                var that = this;
                if (that.isTree) {
                    var nodes = data.filter(m => { return m.Pid == pid; });
                    if (nodes.length) {
                        nodes.forEach(node => {
                            node.children = that.structureTree(data, node.Id);
                        });
                        return nodes;
                    }
                    else if (pid) { return nodes; }
                }
                return data;
            },
            getSummaries(param) {
                const { columns, data } = param;
                const sums = []
                if (this.summaryData) {
                    columns.forEach((column, index) => {
                        if (index != 1) {
                            sums[index] = column.property ? this.summaryData[column.property] : null;
                        }
                        else { sums[index] = "合计"; }

                    });
                }
                return sums;
            },
            getRowById(id) {
                return this.processTableData.find(m => { return m[this.rowKey] == id });
            },
            getRowIndexById(id) {
                return this.processTableData.findIndex(m => { return m[this.rowKey] == id });
            },
            toggleRowExpansion(row, bit) {
                this.$refs.tableRef.toggleRowExpansion(row, bit);
            },
            selectionChange(rowArr) {
                var that = this;
                var ids = [];
                rowArr.forEach(m => {
                    ids.push(m[that.rowKey]);
                });
                that.selectedListIds = ids;
                that.selectedList = rowArr;
                that.isSelected = ids.length > 0;
            },
            searchStyle() {
                return {
                    gridTemplateColumns: `repeat(${this.gridCols}, minmax(0, 1fr))`
                };
            },
            searchToolsStyle() {
                return {
                    gridColumn: `${this.gridCols} / span 1`
                };
            },
            searchItemStyle(index) {
                if (this.collapsed) {
                    if ((index + 2) > this.gridCols) {
                        return { display: "none" }
                    }
                }
                return {};
            },
            handleSizeChange(val) {
                this.queryParams.pageSize = val;
                this.loadData();
            },
            handleCurrentChange(val) {
                this.queryParams.pageNum = val;
                this.loadData();
            },
            search() {
                var that = this;
                that.searchColumns.forEach(m => {
                    var value = $.trim(that.searchParams[m.prop]);
                    if (value) { that.queryParams[m.prop] = value; }
                    else if (that.queryParams[m.prop]) { delete that.queryParams[m.prop]; }
                });
                that.loadData();
            },
            searchInit() {
                var that = this;
                if (that.searchColumns && that.searchColumns.length) {
                    that.searchColumns.forEach(m => {
                        var val = m.default;
                        that.searchParams[m.prop] = val;
                        that.queryParams[m.prop] = val;
                    });
                }
                if (that.baseQuery) {
                    for ([name, baseValue] of Object.entries(that.baseQuery)) {
                        that.queryParams[name] = baseValue;
                    }
                }
                if (that.customParams) {
                    for ([name, customValue] of Object.entries(that.customParams)) {
                        that.queryParams[name] = customValue;
                    }
                }
                if (that.pagination) {
                    that.queryParams["pageNum"] = that.queryParams["pageNum"] || 1;
                    that.queryParams["pageSize"] = that.queryParams["pageSize"] || 10;
                    that.queryParams["total"] = that.queryParams["total"] || 0;
                }
            },
            paramsLoad(params) {
                this.customParams = params;
                this.searchInit();
                this.loadData();
            },
            searchReset() {
                var that = this;
                that.searchInit();
                that.loadData();
            },
            searchAuto(bit) {
                if (bit) { this.search(); };
            }
        },
        mounted() { this.init(); },
        unmounted() { this.destroy(); }
    }
</script>